#include "bsp_uart.h"
#include "usart.h"
#include "wl_queue.h"
#include "amLog.h"
#ifdef PAYLOAD_UART
#include "tcu.h"
#endif
#include "at_parser.h"
#include "commInterface.h"


HAL_StatusTypeDef uart_tx_startDMA(UART_HandleTypeDef *huart, uint8_t* buf, uint16_t size)
{
    return HAL_UART_Transmit_DMA(huart, buf, size);
}

void uart_rx_startDMA(UART_HandleTypeDef *huart, uint8_t* buf, uint8_t size)
{
    HAL_UART_Receive_DMA(huart, buf, size);
    __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    COMM_TYPE_ENUM type;

    type = commGetEntirtyTypeByDevHandler(huart);
    if (type >= COMM_UART_MAX)
    {
        return;
    }

    commEntity[type].tx.busy = 0;
    wl_queue_send_isr(commEntity[type].tx.msgId>>8, commEntity[type].tx.msgId, 0, 0);
}

static int32_t copyDataFromUartDMA(COMM_TYPE_ENUM type, uint16_t cur)
{
    uint16_t offset = 0;

    if (type >= COMM_UART_MAX)
    {
        return -1;
    }

    cur %= commEntity[type].rx.dmaBufSize;
    if (cur == commEntity[type].rx.head)
    {
        return -1;
    }

    if (commEntity[type].rx.head > cur)
    {
        offset = commEntity[type].rx.head;
        if (wl_ringbuf_freeSize(&commEntity[type].rx.ringBuf) == 0 || wl_queue_is_full(commEntity[type].rx.msgId>>8, 1) == 1)
        {
            /* data loss */
            commEntity[type].rx.loss++;
            return -1;
        }

        commEntity[type].rx.head = 0;
        if (commRxRingPush(type, commEntity[type].rx.buf+offset, commEntity[type].rx.dmaBufSize-offset) < 0)
        {
            /* data loss */
            commEntity[type].rx.loss++;
            return -1;
        }

        if (cur == 0)
        {
            return -1;
        }
    }

    offset = commEntity[type].rx.head;
    if (wl_ringbuf_freeSize(&commEntity[type].rx.ringBuf) == 0 || wl_queue_is_full(commEntity[type].rx.msgId>>8, 1) == 1)
    {
        /* data loss */
        commEntity[type].rx.loss++;
        return -1;
    }

    commEntity[type].rx.head = cur%commEntity[type].rx.dmaBufSize;
    if (commRxRingPush(type, commEntity[type].rx.buf+offset, cur-offset) < 0)
    {
        /* data loss */
        commEntity[type].rx.loss++;
        return -1;
    }

    if(type == DEBUG_COMM_TYPE)
    {
        g_u32Port = 0;
        commEntity[type].rx.head = 0;
        HAL_UART_AbortReceive(commEntity[type].comm);
        HAL_UART_Receive_DMA(commEntity[type].comm, commEntity[type].rx.buf, commEntity[type].rx.dmaBufSize);
    }

    return 0;
}

void HAL_UART_RxIdleCallback(UART_HandleTypeDef *huart)
{
    COMM_TYPE_ENUM type;

    type = commGetEntirtyTypeByDevHandler(huart);
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
    {
        __HAL_UART_CLEAR_IDLEFLAG(huart);
        copyDataFromUartDMA(type, commEntity[type].rx.dmaBufSize-__HAL_DMA_GET_COUNTER(huart->hdmarx));
    }
}

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
    COMM_TYPE_ENUM type;

    type = commGetEntirtyTypeByDevHandler(huart);
    if (type != DEBUG_COMM_TYPE)
    {
        copyDataFromUartDMA(type, commEntity[type].rx.dmaBufSize>>1);
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    COMM_TYPE_ENUM type;

    type = commGetEntirtyTypeByDevHandler(huart);
    copyDataFromUartDMA(type, commEntity[type].rx.dmaBufSize);
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    uint32_t errCode;
    COMM_TYPE_ENUM type;

    errCode = HAL_UART_GetError(huart);
    if ((errCode&HAL_UART_ERROR_PE) != 0)
    {
        __HAL_UART_CLEAR_PEFLAG(huart);
    }

    if ((errCode&HAL_UART_ERROR_NE) != 0)
    {
        __HAL_UART_CLEAR_NEFLAG(huart);
    }

    if ((errCode&HAL_UART_ERROR_FE) != 0)
    {
        __HAL_UART_CLEAR_FEFLAG(huart);
    }

    if ((errCode&HAL_UART_ERROR_ORE) != 0)
    {
        __HAL_UART_CLEAR_OREFLAG(huart);
    }

    if ((errCode&HAL_UART_ERROR_DMA) != 0)
    {

    }

    type = commGetEntirtyTypeByDevHandler(huart);
    if (type >= COMM_UART_MAX)
    {
        return;
    }

    if (errCode != HAL_UART_ERROR_NONE && commEntity[type].rx.dmaBufSize != 0 && commEntity[type].rx.buf != NULL)
    {
        huart->RxState = HAL_UART_STATE_READY;
        HAL_UART_Receive_DMA(huart, commEntity[type].rx.buf, commEntity[type].rx.dmaBufSize);
        __HAL_UNLOCK(huart);

        commEntity[type].last_err_code |= errCode;
        commEntity[type].err_cnt++;
        commEntity[type].tx.busy = 0;
    }
}

/* print retarget */
typedef int FILEHANDLE;

__asm(".global __use_no_semihosting\n\t");

void _sys_exit(int x) 
{ 
	x = x; 
} 

int fputc(int ch, FILE *f)
{ 	
	while((DEBUG_UART.Instance->ISR&0X40)==0);
	DEBUG_UART.Instance->RDR=(uint8_t)ch;      
	return ch;
}

int _write(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		while((DEBUG_UART.Instance->ISR&0X40)==0);
		DEBUG_UART.Instance->RDR=(*ptr++);
	}
	return len;
}

int usart1_puts(uint8_t* buffer, uint16_t len)
{ 
    uint16_t i;
    for	(i=0;i<len;i++)
    {
        
        while((DEBUG_UART.Instance->ISR&0X40)==0);
        DEBUG_UART.Instance->RDR=* buffer++;      
    }
    return (int)len;
}

void _ttywrch(int ch)
{
	ch = ch;
}


FILEHANDLE _sys_open(const char *name, int openmode)
{
	return 1;
}

int _sys_close(FILEHANDLE fh)
{
	return 0;
}

int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
{
	//your_device_write(buf, len);
	return 0;
}

int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode)
{
	return -1;
}

int _sys_istty(FILEHANDLE fh)
{
	return 0;
}

int _sys_seek(FILEHANDLE fh, long pos)
{
	return -1;
}

long _sys_flen(FILEHANDLE fh)
{
	return -1;
}

char *_sys_command_string(char *cmd, int len)
{
  return NULL;
}
